package com.duobaoyu.dby.supply.biz.strategy.message.order.base;

import cn.hutool.core.util.ArrayUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.duobaoyu.dby.channel.adapter.bean.message.order.OrderMessage;
import com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderStatusEnum;
import com.duobaoyu.dby.channel.adapter.enums.biz.order.OrderTypeEnum;
import com.duobaoyu.dby.channel.boundary.bean.order.param.OrderCancelParam;
import com.duobaoyu.dby.channel.boundary.template.SupplyChannelTemplate;
import com.duobaoyu.dby.channel.common.util.SupplyCollectionUtils;
import com.duobaoyu.dby.common.mybatis.config.IdGeneratorSnowflake;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.order.OrderBoundaryClient;
import com.duobaoyu.dby.supply.biz.client.product.ProductCenterApiClient;
import com.duobaoyu.dby.supply.biz.constant.DingDingConstants;
import com.duobaoyu.dby.supply.biz.converter.OrderConverter;
import com.duobaoyu.dby.supply.biz.enums.OrderParentTypeEnum;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleService;
import com.duobaoyu.dby.supply.biz.strategy.AbstractChannelMessageAsyncHandler;
import com.duobaoyu.dby.supply.biz.util.DingDingExtUtils;
import com.duobaoyu.dby.supply.biz.util.IdGeneratorUtil;
import com.duobaoyu.dby.supply.common.biz.bo.message.ChannelMessageBO;
import com.duobaoyu.dby.supply.common.biz.bo.message.OrderErrorDingDingMessage;
import com.duobaoyu.dby.supply.common.biz.bo.order.ChannelOrderDetailInBO;
import com.duobaoyu.dby.supply.common.biz.bo.order.ChannelOrderDetailOutBO;
import com.duobaoyu.dby.supply.db.entity.extend.OrderProductResultExtendInfo;
import com.duobaoyu.dby.supply.db.entity.order.Order;
import com.duobaoyu.dby.supply.db.entity.order.OrderProduct;
import com.duobaoyu.dby.supply.db.repository.order.OrderProductRepository;
import com.duobaoyu.dby.supply.db.repository.order.OrderRepository;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 通用方法实现
 *
 * @author fengshaoyu
 * @version 1.0.0
 * @date 2023/10/21 10:43
 */
@Slf4j
public class BaseOrderAsyncHandler extends AbstractChannelMessageAsyncHandler {

	@Resource
	private OrderConverter orderConverter;
	@Resource
	private OrderRepository orderRepository;
	@Resource
	private AfterSaleService afterSaleService;
	@Resource
	private OrderBoundaryClient orderBoundaryClient;
	@Resource
	private IdGeneratorSnowflake idGeneratorSnowflake;
	@Resource
	private SupplyChannelTemplate supplyChannelTemplate;
	@Resource
	private OrderProductRepository orderProductRepository;
	@Resource
	private ProductCenterApiClient productCenterApiClient;

	protected List<Order> getOrderList(ChannelMessageBO channelMessage) {
		List<OrderMessage> orderMessages = this.getMessage(channelMessage);

		List<String> orderTradeSnList = orderMessages.stream().map(OrderMessage::getOrderTradeSn).filter(Objects::nonNull).collect(Collectors.toList());
		List<String> channelOrderSnList = orderMessages.stream().map(OrderMessage::getChannelOrderSn).filter(Objects::nonNull).collect(Collectors.toList());
		List<String> channelOrderParentSnList = orderMessages.stream().map(OrderMessage::getChannelOrderParentSn).filter(Objects::nonNull).collect(Collectors.toList());
		List<String> channelTradeOrderSnList = orderMessages.stream().map(OrderMessage::getChannelTradeOrderSn).filter(Objects::nonNull).collect(Collectors.toList());

		return orderRepository.list(Wrappers.<Order>lambdaQuery()
				.in(CollectionUtils.isNotEmpty(orderTradeSnList), Order::getOrderTradeSn, orderTradeSnList)
				.in(CollectionUtils.isNotEmpty(channelOrderSnList), Order::getChannelOrderSn, channelOrderSnList)
				.in(CollectionUtils.isNotEmpty(channelOrderParentSnList), Order::getChannelOrderParentSn, channelOrderParentSnList)
				.in(CollectionUtils.isNotEmpty(channelTradeOrderSnList), Order::getChannelTradeOrderSn, channelTradeOrderSnList)
				.eq(Order::getParentType, OrderParentTypeEnum.AFTER_SPLIT.getValue())
				.eq(StringUtils.isNotBlank(channelMessage.getChannelCode()), Order::getChannelCode, channelMessage.getChannelCode()));
	}

	protected ChannelOrderDetailOutBO getChannelOrderDetailOut(Order order) {
		ChannelOrderDetailInBO channelOrderDetailIn = new ChannelOrderDetailInBO();
		channelOrderDetailIn.setChannelCode(order.getChannelCode());
		channelOrderDetailIn.setOrderSn(order.getOrderSn());
		channelOrderDetailIn.setOrderTradeSn(order.getOrderTradeSn());
		channelOrderDetailIn.setChannelOrderSn(order.getChannelOrderSn());
		channelOrderDetailIn.setChannelOrderParentSn(order.getChannelOrderParentSn());
		channelOrderDetailIn.setChannelTradeOrderSn(order.getChannelTradeOrderSn());
		if (OrderTypeEnum.isRechargeOrder(order.getOrderType())) {
			List<OrderProduct> list = orderProductRepository.list(Wrappers.lambdaQuery(OrderProduct.class).eq(OrderProduct::getOrderSn, order.getOrderSn()));
			OrderProduct orderProduct = SupplyCollectionUtils.getSingleDataFirst(list, OrderProduct::new);
			channelOrderDetailIn.setOriginalPrice(orderProduct.getOriginalPrice());
		}
		// 订单商品类型同订单类型
		channelOrderDetailIn.setOrderProductTypeSet(Sets.newHashSet(order.getOrderType()));
		return orderBoundaryClient.getChannelOrderDetail(channelOrderDetailIn);
	}

	protected List<OrderMessage> getMessage(ChannelMessageBO channelMessage) {
		Boolean isBatch = Optional.of(channelMessage).map(ChannelMessageBO::getIsBatch).orElse(false);
		return isBatch ?
				JSON.parseArray(channelMessage.getMessage(), OrderMessage.class) :
				Lists.newArrayList(JSON.parseObject(channelMessage.getMessage(), OrderMessage.class));
	}

	protected Order createOrder(Order order, List<OrderProduct> orderProductList) {
		ChannelCodeEnum channelCodeEnum = ChannelCodeEnum.getChannelCodeEnumByCode(order.getChannelCode());
		order.setId(idGeneratorSnowflake.snowflakeId());
		order.setOrderParentSn(order.getOrderSn());
		order.setOrderSn(IdGeneratorUtil.getOrderSn(channelCodeEnum.getCode(), order.getServerName()));
		order.setAfterSalesAllowed(Boolean.TRUE);

		BigDecimal channelPayAmount = orderProductList.stream().map(OrderProduct::getChannelPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
		BigDecimal orderAmount = orderProductList.stream().map(OrderProduct::getPlatformAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
		BigDecimal platformSellAmount = orderProductList.stream().map(OrderProduct::getPlatformSellAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

		order.setChannelOrderAmount(orderAmount);
		order.setOrderAmount(platformSellAmount);
		order.setChannelOrderRealityAmount(channelPayAmount);
		return order;
	}

	protected void reckon(List<OrderProduct> orderProductList) {
		orderProductList.forEach(orderProduct -> {
			orderProduct.setId(idGeneratorSnowflake.snowflakeId());
			orderProduct.setPlatformSellAmount(orderProduct.getPlatformSellPrice().multiply(BigDecimal.valueOf(orderProduct.getSkuNum())));
			orderProduct.setPlatformAmount(orderProduct.getPlatformPrice().multiply(BigDecimal.valueOf(orderProduct.getSkuNum())));
			orderProduct.setChannelPayAmount(orderProduct.getPlatformPrice().multiply(BigDecimal.valueOf(orderProduct.getSkuNum())));
		});
	}

	protected void orderStateCheck(Order order) {
		if (EnumUtils.eq(OrderStatusEnum.FAILURE,order.getOrderStatus())) {
			OrderCancelParam orderCancelParam = new OrderCancelParam();
			orderCancelParam.setChannelCode(order.getChannelCode());
			orderCancelParam.setOrderTradeSn(order.getOrderTradeSn());
			supplyChannelTemplate.cancelOrder(orderCancelParam);
			OrderErrorDingDingMessage orderErrorDingDingMessage = new OrderErrorDingDingMessage();
			orderErrorDingDingMessage.setOrderSn(order.getOrderSn());
			orderErrorDingDingMessage.setChannelCode(order.getChannelCode());
			orderErrorDingDingMessage.setErrorMessage("确认订单失败,回调支付成功");
			DingDingExtUtils.sendMessage(DingDingConstants.BASE_EXCEPTION_MESSAGE_TEXT, orderErrorDingDingMessage);
		}
	}

	@Override
	protected Boolean executeHandler(ChannelMessageBO channelMessage, Object beforeResult) {
		return super.handler(channelMessage, beforeResult);
	}

	/**
	 * 同步订单商品
	 *
	 * @param order              订单
	 * @param channelOrderDetail 渠道订单明细
	 */
	protected void syncOrderProduct(Order order, ChannelOrderDetailOutBO channelOrderDetail) {
		if (Objects.isNull(channelOrderDetail) || Objects.isNull(order)) {
			log.info("同步订单商品结束, 渠道订单明细或订单为空");
			return;
		}
		String channelTradeOrderSn = channelOrderDetail.getChannelTradeOrderSn();
		String orderSn = order.getOrderSn();
		// 同步实物订单商品
		List<ChannelOrderDetailOutBO.RealOrderDetail> realOrderDetailList = channelOrderDetail.getRealOrderDetailList();
		if (CollectionUtils.isNotEmpty(realOrderDetailList)) {
			for (ChannelOrderDetailOutBO.RealOrderDetail realOrderDetail : realOrderDetailList) {
				String channelOrderSn = Optional.ofNullable(realOrderDetail.getChannelOrderSn()).orElse(channelTradeOrderSn);
				// 有的渠道会有多个单, 渠道订单号一致时继续处理
				if (!Objects.equals(channelOrderSn, order.getChannelOrderSn())) {
					continue;
				}
				List<ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo> skuInfos = realOrderDetail.getSkuInfos();
				if (CollectionUtils.isEmpty(skuInfos)) {
					continue;
				}
				// 筛选出同步字段有值的数据
				List<ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo> needSyncDataList = skuInfos.stream().filter(ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo::existsOrderProductSyncData).collect(Collectors.toList());
				if (CollectionUtils.isEmpty(needSyncDataList)) {
					continue;
				}
				Set<String> channelSkuCodeSet = needSyncDataList.stream().map(ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo::getChannelSkuCode).collect(Collectors.toSet());
				Map<String, OrderProduct> channelSkuMap = orderProductRepository.list(Wrappers.lambdaQuery(OrderProduct.class).eq(OrderProduct::getOrderSn, orderSn).in(OrderProduct::getChannelSkuCode, channelSkuCodeSet))
						.stream().collect(Collectors.toMap(OrderProduct::getChannelSkuCode, Function.identity()));
				for (ChannelOrderDetailOutBO.RealOrderDetail.RealOrderSkuInfo realOrderSkuInfo : needSyncDataList) {
					String channelSkuCode = realOrderSkuInfo.getChannelSkuCode();
					OrderProduct orderProduct = channelSkuMap.get(channelSkuCode);
					if (Objects.isNull(orderProduct)) {
						log.info("同步订单商品异常, 未找到渠道订单明细对应的订单商品: orderSn={}, channelSkuCode={}, 渠道订单明细={}", orderSn, channelSkuCode, realOrderSkuInfo);
						DingDingExtUtils.sendMarkdownMsg(String.format("同步订单商品异常, 未找到渠道订单明细对应的订单商品. orderSn=%s, channelSkuCode=%s", orderSn, channelSkuCode));
						continue;
					}
					BigDecimal paymentAmount = realOrderSkuInfo.getPaymentAmount();
					BigDecimal returnFreightAmount = realOrderSkuInfo.getChannelReturnFreightAmount();
					Integer returnSkuNum = realOrderSkuInfo.getChannelReturnSkuNum();
					boolean change = false;
					OrderProduct updateObj = new OrderProduct();
					updateObj.setId(orderProduct.getId());
					// 订单商品总金额是否变动
					if (Objects.nonNull(paymentAmount) && !(Objects.nonNull(orderProduct.getChannelPayAmount()) && paymentAmount.compareTo(orderProduct.getChannelPayAmount()) == 0)) {
						updateObj.setChannelPayAmount(paymentAmount);
						change = true;
					}
					// 渠道退款运费金额是否变动
					if (Objects.nonNull(returnFreightAmount) && !(Objects.nonNull(orderProduct.getChannelReturnFreightAmount()) && returnFreightAmount.compareTo(orderProduct.getChannelReturnFreightAmount()) == 0)) {
						updateObj.setChannelReturnFreightAmount(returnFreightAmount);
						change = true;
					}
					// 渠道退款商品数量是否变动
					if (Objects.nonNull(returnSkuNum) && !Objects.equals(returnSkuNum, orderProduct.getChannelReturnSkuNum())) {
						updateObj.setChannelReturnSkuNum(returnSkuNum);
						change = true;
					}
					if (change) {
						log.info("开始更新订单商品: orderSn={}, skuCode={}, data={}", orderSn, orderProduct.getSkuCode(), updateObj);
						boolean b = orderProductRepository.updateById(updateObj);
						log.info("更新订单商品结果: {}", b);
					}
				}
			}
		}

		// 同步虚拟订单商品
		List<ChannelOrderDetailOutBO.VirtualOrderDetail> virtualOrderDetailList = channelOrderDetail.getVirtualOrderDetailList();
		if (CollectionUtils.isNotEmpty(virtualOrderDetailList)) {
			for (ChannelOrderDetailOutBO.VirtualOrderDetail virtualOrderDetail : virtualOrderDetailList) {
				// 筛选出同步字段有值的数据
				if (!virtualOrderDetail.existsOrderProductSyncData()) {
					continue;
				}
				String channelOrderSn = Optional.ofNullable(virtualOrderDetail.getChannelOrderSn()).orElse(channelTradeOrderSn);
				List<OrderProduct> orderProductList = orderProductRepository.list(Wrappers.lambdaQuery(OrderProduct.class).eq(OrderProduct::getOrderSn, orderSn)
						.eq(Objects.nonNull(virtualOrderDetail.getChannelSkuCode()), OrderProduct::getChannelSkuCode, virtualOrderDetail.getChannelSkuCode()));

				if (CollectionUtils.isEmpty(orderProductList)) {
					if(log.isDebugEnabled()) {
						log.debug("同步订单虚拟商品异常, 未找到渠道订单明细对应的订单商品: orderSn={}, channelOrderSn={}, 渠道虚拟订单明细={}", orderSn, channelOrderSn, JSON.toJSONString(virtualOrderDetail));
					}
					DingDingExtUtils.sendMarkdownMsg(String.format("同步订单虚拟商品异常, 未找到渠道订单明细对应的订单商品. orderSn=%s", orderSn));
					continue;
				}
				if (orderProductList.size() > 1) {
					if(log.isDebugEnabled()) {
						log.debug("同步订单虚拟商品异常, 找到多条订单商品数据: orderSn={}, channelOrderSn={}, 渠道虚拟订单明细={}", orderSn, channelOrderSn, JSON.toJSONString(virtualOrderDetail));
					}
					DingDingExtUtils.sendMarkdownMsg(String.format("同步订单虚拟商品异常, 找到多条订单商品数据. orderSn=%s", orderSn));
					continue;
				}
				OrderProduct orderProduct = SupplyCollectionUtils.getSingleData(orderProductList);
				BigDecimal channelOrderAmount = virtualOrderDetail.getChannelOrderAmount();
				BigDecimal actualAmount = virtualOrderDetail.getActualAmount();
				List<ChannelOrderDetailOutBO.VirtualOrderDetail.Card> cardList = virtualOrderDetail.getCardList();
				boolean change = false;
				OrderProduct updateObj = new OrderProduct();
				updateObj.setId(orderProduct.getId());
				// 订单商品总金额是否变动
				if (Objects.nonNull(channelOrderAmount) && !(Objects.nonNull(orderProduct.getChannelPayAmount()) && channelOrderAmount.compareTo(orderProduct.getChannelPayAmount()) == 0)) {
					updateObj.setChannelPayAmount(channelOrderAmount);
					change = true;
				}
				// 实际到账金额
				if (Objects.nonNull(actualAmount) && !(Objects.nonNull(orderProduct.getActualAmount()) && actualAmount.compareTo(orderProduct.getActualAmount()) == 0)) {
					updateObj.setActualAmount(actualAmount);
					change = true;
				}
				// 卡券信息
				List<OrderProductResultExtendInfo.CouponInfo> couponInfoList = Optional.ofNullable(orderProduct.getResultExtend()).map(OrderProductResultExtendInfo::getCouponInfo).orElse(null);
				if (CollectionUtils.isNotEmpty(cardList) && CollectionUtils.isNotEmpty(couponInfoList)) {
					List<OrderProductResultExtendInfo.CouponInfo> channelCouponInfoList = cardList.stream().map(orderConverter::toOrderProductResultCouponInfoExtendInfo).collect(Collectors.toList());
					if (!ArrayUtil.equals(couponInfoList, channelCouponInfoList)) {
						OrderProductResultExtendInfo orderProductResultExtendInfo = Optional.ofNullable(orderProduct.getResultExtend()).orElse(new OrderProductResultExtendInfo());
						orderProductResultExtendInfo.setCouponInfo(channelCouponInfoList);
						updateObj.setResultExtend(orderProductResultExtendInfo);
						change = true;
					}
				}

				if (change) {
					log.info("开始更新订单商品: orderSn={}, skuCode={}, data={}", orderSn, orderProduct.getSkuCode(), updateObj);
					boolean b = orderProductRepository.updateById(updateObj);
					log.info("更新订单商品结果: {}", b);
				}

				// 虚拟订单校验订单价格
				if (OrderTypeEnum.getOrderTypeEnum(order.getOrderType()) != OrderTypeEnum.REAL_ORDER) {
					if (Objects.nonNull(channelOrderDetail.getChannelOrderAmount()) && order.getChannelOrderAmount().compareTo(channelOrderDetail.getChannelOrderAmount()) < 0) {
						log.info("订单状态同步,虚拟订单渠道总价不一致,对订单商品进行下架: order={}, channelOrderInfo={}", com.alibaba.fastjson.JSON.toJSONString(order), com.alibaba.fastjson.JSON.toJSONString(channelOrderDetail));
						List<String> skuCodeList = orderProductList.stream().map(OrderProduct::getSkuCode).distinct().collect(Collectors.toList());
						productCenterApiClient.offShelfProducts(skuCodeList);
					}
				}
			}

		}
	}

	/**
	 * 已发货的订单售后单处理
	 */
	protected void afterSaleHandle(Order order){
		try{
			afterSaleService.changeSystemCreateAfterSaleFail(order.getOrderSn());
		}catch(Exception e){
			log.warn("已发货订单:{}无售后单不处理", JSON.toJSONString(order.getOrderSn()));
		}
	}
}
